{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "# Load environment variables from openai.env file\n",
    "load_dotenv(\"openai.env\")\n",
    "\n",
    "# Read the OPENAI_API_KEY from the environment\n",
    "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "api_base = os.getenv(\"OPENAI_API_BASE\")\n",
    "os.environ[\"OPENAI_API_KEY\"] = api_key\n",
    "os.environ[\"OPENAI_API_BASE\"] = api_base"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LCEL:memory添加方式\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from operator import itemgetter\n",
    "\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
    "from langchain_core.runnables import RunnableLambda, RunnablePassthrough\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI()\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"你是一个乐于助人的机器人\"),\n",
    "        MessagesPlaceholder(variable_name=\"history\"),\n",
    "        (\"human\", \"{input}\"),\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "memory = ConversationBufferMemory(return_messages=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'history': []}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "memory.load_memory_variables({})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "增加一条链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = (\n",
    "    RunnablePassthrough.assign(\n",
    "        history=RunnableLambda(memory.load_memory_variables) | itemgetter(\"history\")\n",
    "    )\n",
    "    | prompt\n",
    "    | model\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='你好Tomie！有什么我可以帮助你的吗？')"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inputs = {\"input\": \"你好我是tomie\"}\n",
    "response = chain.invoke(inputs)\n",
    "response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'history': [HumanMessage(content='你好我是tomie'),\n",
       "  AIMessage(content='你好Tomie！有什么我可以帮助你的吗？')]}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#保存记忆\n",
    "memory.save_context(inputs, {\"output\": response.content})\n",
    "memory.load_memory_variables({})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='你自己说你叫Tomie。')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inputs = {\"input\": \"我叫什么名字?\"}\n",
    "response = chain.invoke(inputs)\n",
    "response"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用Redis来实现长时记忆"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! pip install redis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Optional\n",
    "\n",
    "from langchain_community.chat_message_histories import RedisChatMessageHistory\n",
    "from langchain_community.chat_models import ChatOpenAI\n",
    "from langchain_core.chat_history import BaseChatMessageHistory\n",
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
    "from langchain_core.runnables.history import RunnableWithMessageHistory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/tomiezhang/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The class `langchain_community.chat_models.openai.ChatOpenAI` was deprecated in langchain-community 0.0.10 and will be removed in 0.2.0. An updated version of the class exists in the langchain-openai package and should be used instead. To use it run `pip install -U langchain-openai` and import as `from langchain_openai import ChatOpenAI`.\n",
      "  warn_deprecated(\n"
     ]
    }
   ],
   "source": [
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"你是一个擅长{ability}的助手\"),\n",
    "        MessagesPlaceholder(variable_name=\"history\"),\n",
    "        (\"human\", \"{question}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "chain = prompt | ChatOpenAI(model=\"gpt-4-1106-preview\",temperature=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain_with_history = RunnableWithMessageHistory(\n",
    "    chain,\n",
    "    #使用redis存储聊天记录\n",
    "    lambda session_id: RedisChatMessageHistory(session_id, url=\"redis://localhost:6379/0\"),\n",
    "    input_messages_key=\"question\",\n",
    "    history_messages_key=\"history\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='中国建都时间最长的城市是西安。西安（古称长安）在中国历史上曾多次成为国都，包括周、秦、汉、隋、唐等多个朝代。累计建都时间超过1200年，是中国历史上建都时间最长的城市。')"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#每次调用都会保存聊天记录，需要有对应的session_id\n",
    "chain_with_history.invoke(\n",
    "    {\"ability\": \"历史\", \"question\": \"中国建都时间最长的城市是哪个?\"},\n",
    "    config={\"configurable\": {\"session_id\": \"tomiezhang\"}},\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='西安（古称长安）作为中国历史上的重要都城，累计建都时间超过1200年。以下是主要的几个朝代及其建都年份：\\n\\n1. 西周（前1046年 - 前771年）：西周时期，周王朝的都城在今天的西安西北部的镐京（又称镐邑或者宗周），这是周王朝的早期都城。\\n\\n2. 秦朝（前221年 - 前206年）：秦始皇统一六国后，将都城定在咸阳，咸阳紧邻今天的西安市，是秦朝的政治中心。\\n\\n3. 西汉（前206年 - 9年）：西汉初期，汉高祖刘邦定都长安，长安城位于今天的西安市区。\\n\\n4. 新朝（9年 - 23年）：王莽篡汉自立，改国号为“新”，都城依然是长安。\\n\\n5. 东汉（25年 - 220年）：东汉虽然定都洛阳，但长安依然是重要的政治、经济中心。\\n\\n6. 西晋（265年 - 316年）：西晋建都长安，但由于“八王之乱”和“永嘉之乱”，西晋在长安的统治并不稳定。\\n\\n7. 前赵（304年 - 329年）：五胡乱华期间，汉赵（前赵）在长安一带建立政权。\\n\\n8. 前秦（351年 - 394年）：苻坚建立前秦后，也曾将都城设在长安。\\n\\n9. 西魏（535年 - 557年）：西魏在长安建都。\\n\\n10. 北周（557年 - 581年）：北周继续在长安建都。\\n\\n11. 隋朝（581年 - 618年）：隋文帝和隋炀帝时期，都城在大兴城，即后来的长安城，也就是今天的西安。\\n\\n12. 唐朝（618年 - 907年）：唐朝是长安最为繁荣的时期，唐长安是当时世界上最大的城市之一，对外开放，文化交流频繁。\\n\\n综上所述，西安作为都城的历史跨越了周、秦、汉、晋、隋、唐等多个朝代，累计时间超过1200年。需要注意的是，这里的年份并不是连续的，因为在不同的历史时期，有些朝代的都城并不在长安。')"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain_with_history.invoke(\n",
    "    {\"ability\": \"历史\", \"question\": \"它有多少年建都历史？\"},\n",
    "    config={\"configurable\": {\"session_id\": \"tomiezhang\"}},\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchains",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
      